/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#include "MkPsFileSource.h"
#include "MkEvent/MkTimer.h"

CMkPsFileSource::CMkPsFileSource(FILE *fp, CMkTimer* pTimer)
    :CMkFileSource(MkMediaSourceFilePs, fp, pTimer)
{

}

Uint32 CMkPsFileSource::ScanFile()
{
    CMkPsDemuxer PsDemuxer;
    Uint32 nTotalOffset = 0;
    while (TRUE) {
        Uint32 nToRead = m_MaxLen - m_nOffset;
        int nRead = fread(m_pBuf + m_nOffset, 1, nToRead, m_pFp);
        if (nRead <= 0) {
            break;
        }
        m_nOffset += nRead;
        Uint8* pNextPsHeader = nullptr;
        Uint8* pLastHeader = m_pBuf;
        CMkPsDemuxer::GetPsHeader(pLastHeader, m_nOffset - (pLastHeader - m_pBuf), &pNextPsHeader);
        pLastHeader = pNextPsHeader;
        while (NoneError == CMkPsDemuxer::GetPsHeader(pLastHeader + 4, m_nOffset - (pLastHeader - m_pBuf) - 4, &pNextPsHeader)) {
            MkFilePacketParam PacketParam;
            PacketParam.VecPacket.push_back(std::pair<Uint32, Uint32>(nTotalOffset + pLastHeader - m_pBuf, pNextPsHeader - pLastHeader));
            m_VecPacket.push_back(PacketParam);
            if (MkCodecUnknown == PsDemuxer.GetVideoParam().GetCodec()
                || MkCodecUnknown == PsDemuxer.GetAudioParam().GetCodec()
                || (MkCodecUnknown != PsDemuxer.GetVideoParam().GetCodec()
                    && 0 == PsDemuxer.GetVideoParam().GetFrameRate())) {
                PsDemuxer.InputPsPacket(pLastHeader, pNextPsHeader - pLastHeader);
            }
            pLastHeader = pNextPsHeader;
        }
        if (nRead == nToRead) {
            nTotalOffset += pLastHeader - m_pBuf;
            m_nOffset -= pLastHeader - m_pBuf;
            memmove(m_pBuf, pLastHeader, m_nOffset);
        } else {
            MkFilePacketParam PacketParam;
            PacketParam.VecPacket.push_back(std::pair<Uint32, Uint32>(nTotalOffset + pLastHeader - m_pBuf, m_pBuf + m_nOffset - pLastHeader));
            m_VecPacket.push_back(PacketParam);
        }
    }
    SetVideoParam(PsDemuxer.GetVideoParam());
    SetAudioParam(PsDemuxer.GetAudioParam());
    return NoneError;
}

Uint32 CMkPsFileSource::GetNextFrame(MkVector<MkEsPacket>& VecEsPacket)
{
    MkEsPacket EsPacket;
    if (m_ReadFrameIndex >= m_VecPacket.size()) {
        if (m_pTimer) {
            m_pTimer->DeleteTimer(m_FrameGetTimer);
        }
        EsPacket.Pts = EsPacket.Dts = 0;
        EsPacket.CodecType = GetVideoParam().GetCodec();
        EsPacket.bKeyPacket = TRUE;
        VecEsPacket.push_back(EsPacket);
    } else {
        MkFilePacketParam PacketParam = m_VecPacket[m_ReadFrameIndex];
        m_ReadFrameIndex++;
        fseek(GetFp(), PacketParam.VecPacket.begin()->first, SEEK_SET);
        fread(m_pBuf, 1, PacketParam.VecPacket.begin()->second, GetFp());
        m_PsDemuxer.InputPsPacket(m_pBuf, PacketParam.VecPacket.begin()->second);
        while (NoneError == m_PsDemuxer.GetEsPacket(EsPacket)) {
            EsPacket.Dts = EsPacket.Pts = m_Pts;
            if (MkCodecCavs > EsPacket.CodecType) {
                m_Pts += static_cast<Uint32>(1000 / (GetVideoParam().GetFrameRate()*GetSpeed()));
            }
            if (GetSpeed() >= 8.0 && !EsPacket.bKeyPacket) {
                continue;
            }
            VecEsPacket.emplace_back(EsPacket); //a full ps packet
        }
    }
    return NoneError;
}

CMkPsFileSource::~CMkPsFileSource()
{

}

